--
-- Shadow priest rotation helper
--

-- '_G' stuff is to keep lualint happy

if _G['select'](2, _G['UnitClass']('player')) ~= 'PRIEST' then return end

-------------------------------------------
-- Local references to globals for speed and lint's happiness
-------------------------------------------
local _G = _G

local UnitHealth = _G['UnitHealth']
local strsplit = _G['strsplit']
local max = _G['max']
local GetTime = _G['GetTime']

local Rotor = _G['Rotor']

--------------------
local MODULE = 'Shadow Priest'

-------------------------------------------
-- Constants
-------------------------------------------

--
-- Spell ids
--
local MB_ID     = 8092  -- mind blast
local SWP_ID    = 589   -- shadow word: pain
local VT_ID     = 34914 -- vampiric touch
local DP_ID     = 2944  -- devouring plague
local MF_ID     = 15407 -- mind flay
local SWD_ID    = 32379 -- shadow word: death

-- Debuff ids
local SWP_DEBUFF_ID = SWP_ID
local VT_DEBUFF_ID  = VT_ID
local DP_DEBUFF_ID  = DP_ID

-- The module
local Mod = Rotor:NewModule(MODULE)

---------------------------------------------------------
--
-- Spell prediction
--

-- Spell objects
local swd -- shadow word: death
local mb -- mind blast
local swp -- shadow word: pain
local vt -- vampiric touch
local dp -- devouring plague

-- Buff objects

-- Debuff objects
local vt_debuff -- vampiric touch
local swp_debuff -- shadow word: pain
local dp_debuff -- devouring plague

-- Local vars
local now = 0
local gcd = 0

--
-- Methods implementation
--

function Mod:RegisterAuras()
    vt_debuff = Rotor:RegisterDebuff(VT_DEBUFF_ID, true)
    swp_debuff = Rotor:RegisterDebuff(SWP_DEBUFF_ID, true)
    dp_debuff = Rotor:RegisterDebuff(DP_DEBUFF_ID, true)
end

function Mod:RegisterSpells()
    mb = Rotor:RegisterSpell(MB_ID)
    swd = Rotor:RegisterSpell(SWD_ID)
    swp = Rotor:RegisterSpell(SWP_ID)
    vt = Rotor:RegisterSpell(VT_ID)
    dp = Rotor:RegisterSpell(DP_ID)
end

function Mod:Init(opts)
    self:RegisterAuras()
    self:RegisterSpells()
    return true
end

local function CheckUnsent(spell, time_since_last_sent)
    return (spell.sentAt <= spell.doneAt) and (spell.doneAt + (time_since_last_sent or 0.5) < now)
end

local function CheckOffCdAndUnsent(spell, time_since_last_sent, wth)
    return (spell.cd - (wth or 0.4) <= gcd) and CheckUnsent(spell, time_since_last_sent)
end

local at_max_level = _G['UnitLevel']('player') == _G['MAX_PLAYER_LEVEL']
local dots_max_hp_threshold
if at_max_level then
    dots_max_hp_threshold = 300000
else
    dots_max_hp_threshold = 80000
end

function Mod:NextSkill(gcd_arg, cur_spell)
    gcd = max(0.5, gcd_arg)
    now = GetTime()

    local use_dots = (Rotor.target_max_hp > dots_max_hp_threshold)

    if (UnitHealth('target') / Rotor.target_max_hp < 0.25) and CheckOffCdAndUnsent(swd, 1.5) then
        return SWD_ID
    end

    if use_dots and (vt_debuff.time_left < 2) and CheckUnsent(vt, 2) then
        return VT_ID
    end

    if use_dots and (dp_debuff.time_left < 2) and CheckUnsent(dp, 2) then
        return DP_ID
    end

    if use_dots and (swp_debuff.time_left < 2) and CheckUnsent(swp, 2) then
        return SWP_ID
    end

    if CheckOffCdAndUnsent(mb, 3) then
        return MB_ID
    end

    return MF_ID
end

-- Command line handler
function Mod:HandleCommandLine(cmd)
    local cmd, args = strsplit(' ', (cmd or ''):lower(), 2)
    -- handle command line here
end

-- Module detection
function Mod:Detect()
    return Rotor.spec == 3
end
